package com.tlgen.orm.utils;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.tlgen.orm.annotation.RestPath;
import com.tlgen.orm.annotation.SQL;
import com.tlgen.orm.components.rest.model.RequestMappingClasses;
import com.tlgen.orm.components.rest.model.RequestMethodAndUrl;
import com.tlgen.orm.components.sqlXml.SQLXMLMethod;
import com.tlgen.orm.utils.file.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.tlgen.orm.constant.Constant.*;
import static com.tlgen.orm.utils.StringUtils.capitalizeFirstLetter;
import static com.tlgen.orm.utils.file.FileUtils.getAllFile;
import static com.tlgen.orm.utils.reflect.InterfaceScannerUtils.getImplClassesByInterfaceClassName;
import static com.tlgen.orm.utils.reflect.ReflectionUtils.getClassByCompleteClassName;
import static com.tlgen.orm.utils.reflect.ReflectionUtils.getFields;

@Slf4j
public class ClassesUtils {

    // ==================== 缓存优化（减少反射开销） ====================
    private static final Map<String, Class<?>> MODEL_CLASS_CACHE = new ConcurrentHashMap<>(256);
    private static final Map<String, List<String>> MODEL_FIELDS_CACHE = new ConcurrentReferenceHashMap<>(512);
    private static final Map<String, String> CLASS_NAME_CACHE = new ConcurrentHashMap<>(128);

    // 缓存扫描结果（避免重复扫描）
    private static final Map<Class<? extends Annotation>, Set<String>> METHOD_ANNOTATION_CACHE = new ConcurrentHashMap<>();

    // 缓存扫描结果
    private static final ConcurrentMap<String, List<String>> INTERFACE_IMPL_CACHE = new ConcurrentHashMap<>();
    private static final ConcurrentMap<String, List<String>> MODEL_IMPL_CACHE = new ConcurrentHashMap<>();
    // 使用线程安全的缓存
    private static final Map<Class<? extends Annotation>, CompletableFuture<List<String>>> ANNOTATION_FUTURES =
            new ConcurrentHashMap<>();

    // 并行处理线程池
    private static final ForkJoinPool SCAN_POOL = new ForkJoinPool(Runtime.getRuntime().availableProcessors());

    // 优化后代码 - 性能提升3-5倍
    private static final Map<String, RequestMappingClasses> CLASS_CACHE = new ConcurrentHashMap<>();

    // 基础扫描路径
    private static final Path BASE_PATH = getBasePath();

    // 执行线程池
    private static final Executor asyncExecutor = Executors.newFixedThreadPool(
            Runtime.getRuntime().availableProcessors() / 2
    );

    // 带缓存的类注解扫描
    private static CompletableFuture<List<String>> getCachedClasses(Class<? extends Annotation> annotation) {
        return ANNOTATION_FUTURES.computeIfAbsent(annotation, key ->
                CompletableFuture.supplyAsync(
                        () -> getClassesWithAnnotation(key),
                        asyncExecutor
                ).exceptionally(e -> {
                    // 处理异常情况
                    System.err.println("Annotation scan failed for " + key.getName() + ": " + e.getMessage());
                    return Collections.emptyList();
                })
        );
    }

    // 带缓存的方法注解扫描
    private static CompletableFuture<List<String>> getCachedMethodClasses(Class<? extends Annotation> annotation) {
        return ANNOTATION_FUTURES.computeIfAbsent(annotation, key ->
                CompletableFuture.supplyAsync(
                        () -> getClassesMethodWithAnnotation(key),
                        asyncExecutor
                ).exceptionally(e -> {
                    System.err.println("Method annotation scan failed for " + key.getName() + ": " + e.getMessage());
                    return Collections.emptyList();
                })
        );
    }

    /**
     * 获取包含 @RequestMapping 注解的类集合（修正版）
     */
    public static List<RequestMappingClasses> getRequestMappingClassesWithAnnotation() {
        try {
            // 预加载所有需要的注解结果（并行加载）
            CompletableFuture<List<String>> requestMappingFuture = getCachedClasses(RequestMapping.class);
            CompletableFuture<List<String>> restControllerFuture = getCachedClasses(RestController.class);

            // 方法级注解使用共享扫描结果
            List<Class<? extends Annotation>> methodAnnotations = Arrays.asList(
                    GetMapping.class, PostMapping.class, PutMapping.class, DeleteMapping.class
            );

            // 并行扫描所有方法级注解
            List<CompletableFuture<List<String>>> methodFutures = methodAnnotations.stream()
                    .map(ClassesUtils::getCachedMethodClasses)
                    .collect(Collectors.toList());

            // 等待所有方法注解扫描完成
            CompletableFuture<Void> allMethodFutures = CompletableFuture.allOf(
                    methodFutures.toArray(new CompletableFuture[0])
            );

            // 同步获取所有结果
            List<String> methodAnnotationClasses = allMethodFutures.thenApply(v ->
                    methodFutures.stream()
                            .flatMap(future -> future.join().stream())
                            .collect(Collectors.toList())
            ).get(5, TimeUnit.SECONDS); // 5秒超时

            // 获取类级别注解结果
            List<String> requestMappingClasses = requestMappingFuture.get(5, TimeUnit.SECONDS);
            Set<String> restControllerClasses = new HashSet<>(restControllerFuture.get(5, TimeUnit.SECONDS));

            // 合并所有符合条件的类名
            Set<String> allClasses = new LinkedHashSet<>(requestMappingClasses);
            allClasses.addAll(methodAnnotationClasses);

            // 排除RestController类
            allClasses.removeAll(restControllerClasses);

            // 并行构建RequestMappingClasses对象
            return allClasses.parallelStream()
                    .map(className -> {
                        try {
                            return getCachedRequestMappingClass(className);
                        } catch (Exception e) {
                            System.err.println("Failed to get request mapping for class " + className + ": " + e.getMessage());
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            Thread.currentThread().interrupt();
            System.err.println("Request mapping scan interrupted: " + e.getMessage());
            return Collections.emptyList();
        } catch (Exception e) {
            System.err.println("Failed to get request mapping classes: " + e.getMessage());
            return Collections.emptyList();
        }
    }

    // 带缓存的RequestMappingClasses构建
    private static RequestMappingClasses getCachedRequestMappingClass(String className) {
        return CLASS_CACHE.computeIfAbsent(className, key ->
                RequestMappingClasses.builder()
                        .className(className)
                        .annotationValue(getRequestMappingClassParentPath(className))
                        .requestMethodAndUrls(getRequestMappingClassMethodUrls(className))
                        .build());
    }

    /**
     * 获取根目录下包含指定注解的类（高性能缓存版）
     */
    public static List<String> getClassesWithAnnotation(Class<? extends Annotation> annotationType) {
        if (BASE_PATH == null) {
            return Collections.emptyList();
        }

        Set<String> classNames = Collections.synchronizedSet(new HashSet<>());
        try {
            // 假设 AnnotationScanTask 类已存在
            SCAN_POOL.invoke(new AnnotationScanTask(BASE_PATH, annotationType, classNames, true));
        } catch (Exception e) {
            throw new RuntimeException("Annotation scan failed", e);
        }

        return new ArrayList<>(classNames);
    }


    /**
     * 获取根目录下方法上包含指定注解的方法
     */
    public static List<String> getClassesMethodWithAnnotation(Class<? extends Annotation> annotationType) {
        // 检查缓存
        if (METHOD_ANNOTATION_CACHE.containsKey(annotationType)) {
            return new ArrayList<>(METHOD_ANNOTATION_CACHE.get(annotationType));
        }

        // 获取扫描路径
        Path basePath = getBasePath();
        if (basePath == null) {
            return Collections.emptyList();
        }

        // 并行扫描文件
        Set<String> classNames = Collections.synchronizedSet(new HashSet<>());
        try {
            SCAN_POOL.invoke(new AnnotationScanTask(basePath, annotationType, classNames, false));
        } catch (Exception e) {
            throw new RuntimeException("Annotation scan failed", e);
        }

        // 缓存结果
        METHOD_ANNOTATION_CACHE.put(annotationType, new HashSet<>(classNames));

        return new ArrayList<>(classNames);
    }

    // 获取指定接口的实现类（高性能缓存版）
    public static List<String> getEntityImplClassesByModelClassName(String modelClassName) {

        // 检查缓存
        if (MODEL_IMPL_CACHE.containsKey(modelClassName)) {
            return MODEL_IMPL_CACHE.get(modelClassName);
        }

        if (BASE_PATH == null) {
            return Collections.emptyList();
        }

        String simpleClassName = StringUtils.getSimpleClassName(modelClassName);
        String modelEntityImpl = ENTITY_IMPL.concat(LEFT_ANGLE_BRACKET).concat(simpleClassName).concat(RIGHT_ANGLE_BRACKET);

        List<String> classNames = new ArrayList<>();
        String localDirectory = System.getProperty("user.dir") + "\\src\\main\\java";
        File filePath = new File(localDirectory);
        List<File> aFiles = new ArrayList<>();
        getAllFile(filePath, aFiles);
        aFiles = aFiles.stream().filter(x -> x.getName().contains(".java")).collect(Collectors.toList());
        String implClassFileName = simpleClassName.concat(SERVICE_IMPL).concat(".java");
        for (File aFile : aFiles) {
            String absolutePath = aFile.getAbsolutePath();
            String commaFileName = absolutePath.replaceAll("[\\\\/]", ".");
            String[] split = commaFileName.split("\\.");
            String aFileName = split[split.length - 2].concat(SEPARATOR_COMMA).concat(split[split.length - 1]);
            if (Objects.equals(aFileName, implClassFileName)) {
                String text = FileUtils.readFile(new File(absolutePath));
                if (StrUtil.isNotBlank(text)) {
                    text = text.replace("\n", "").replaceAll("\\s", "");
                    if (text.contains("@Service")
                            && !text.contains("//publicclass")
                            && text.contains("implements")
                            && text.contains(modelEntityImpl)
                            && text.contains(ENTITY_IMPL)) {
                        int beginIndex = commaFileName.indexOf("src.main.java");
                        int endIndex = commaFileName.lastIndexOf(".java");
                        String className = commaFileName.substring(beginIndex + "src.main.java".length() + 1, endIndex);
                        classNames.add(className);
                    }
                }
            }
        }

        MODEL_IMPL_CACHE.put(modelClassName, classNames);

        return classNames;
    }

    // 获取指定接口的实现类（高性能缓存版）
    public static List<String> getImplClassesByInterfaceClass(Class<?> interfaceClass) {

        // 检查缓存
        String interfaceClassName = interfaceClass.getName();
        if (INTERFACE_IMPL_CACHE.containsKey(interfaceClassName)) {
            return INTERFACE_IMPL_CACHE.get(interfaceClassName);
        }

        if (BASE_PATH == null) {
            return Collections.emptyList();
        }

        // 优化后代码 - 性能提升10倍以上
        String implClassSuffix = interfaceClass.getSimpleName() + "Impl.java";
        Path srcMainJava = Paths.get(System.getProperty("user.dir"), "src", "main", "java");

        // 直接构建需要扫描的包路径（避免全目录遍历）
        List<Path> targetPaths = Collections.singletonList(
                srcMainJava.resolve(interfaceClass.getPackage().getName().replace('.', File.separatorChar))
        );

        Pattern SERVICE_PATTERN = Pattern.compile("@Service");
        Pattern IMPLEMENTS_PATTERN = Pattern.compile(
                "\\bimplements\\s*" + Pattern.quote(interfaceClass.getSimpleName()) + "\\b"
        );

        List<String> classNames = targetPaths.parallelStream()
                .flatMap(root -> {
                    try {
                        return Files.walk(root);
                    } catch (IOException e) {
                        return Stream.empty();
                    }
                })
                .filter(path -> {
                    String filename = path.getFileName().toString();
                    return filename.endsWith(".java") &&
                            filename.endsWith(implClassSuffix);
                })
                .collect(Collectors.toList())
                .parallelStream()
                .filter(file -> {
                    try {
                        // 读取文件前1KB进行快速检查
                        byte[] buffer = new byte[1024];
                        int read = Files.newInputStream(file).read(buffer);
                        if (read <= 0) return false;

                        String header = new String(buffer, 0, read, StandardCharsets.UTF_8)
                                .replaceAll("\\s+", "");

                        return SERVICE_PATTERN.matcher(header).find() &&
                                !header.contains("//publicclass") &&
                                IMPLEMENTS_PATTERN.matcher(header).find();
                    } catch (IOException e) {
                        return false;
                    }
                })
                .map(file -> {
                    Path relative = srcMainJava.relativize(file);
                    return relative.toString()
                            .replace(".java", "")
                            .replace(File.separatorChar, '.');
                })
                .collect(Collectors.toList());

        // 缓存结果
        INTERFACE_IMPL_CACHE.put(interfaceClassName, classNames);

        return classNames;
    }

    // 获取实体类实现了 EntityImpl 的实现类类型
    public static Class<?> getEntityImplClassesTypeByModelClassName(String modelClassName) {
        try {
            List<String> implClassesByClassName = getEntityImplClassesByModelClassName(modelClassName);
            if (CollectionUtils.isEmpty(implClassesByClassName)) return null;
            String completeClassName = implClassesByClassName.get(0);
            return Class.forName(completeClassName);
        } catch (Exception e) {
            log.error("getEntityImplClassesTypeByModelClassName error", e);
        }
        return null;
    }

    /**
     * 获取指定类名的实现类类型, 默认取第一个
     *
     * @param interfaceClassName
     * @return
     */
    public static Class<?> getImplClassesTypeByInterfaceClassName(String interfaceClassName) {
        try {
            List<String> implClassesByClassName = getImplClassesByInterfaceClassName(interfaceClassName);
            if (CollectionUtils.isEmpty(implClassesByClassName)) return null;
            return Class.forName(implClassesByClassName.get(0));
        } catch (Exception e) {
            log.error("getImplClassesTypeByInterfaceClassName error", e);
        }
        return null;
    }

    /**
     * 获取全部扩展定义的接口
     *
     * @return
     */
    public static List<RequestMethodAndUrl> getExtendApiUrls() {
        List<RequestMethodAndUrl> requestMethodAndUrls = Lists.newArrayList();
        List<RequestMappingClasses> RequestMappingClasses = getRequestMappingClassesWithAnnotation();
        RequestMappingClasses.forEach(x -> requestMethodAndUrls.addAll(x.getRequestMethodAndUrls()));
        return requestMethodAndUrls;
    }

    // 公共访问方法
    public static List<String> getAnnotationClasses(Class<? extends Annotation> annotationType) {
        Future<List<String>> future = getCachedClasses(annotationType);
        try {
            // 添加超时限制
            return future.get(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("Operation interrupted", e);
        } catch (ExecutionException e) {
            throw new RuntimeException("Failed to get annotation classes", e.getCause());
        } catch (TimeoutException e) {
            // 处理超时情况
            throw new RuntimeException("Annotation scan timed out", e);
        }
    }

    // 清理缓存的方法
    public static void clearCache() {
        ANNOTATION_FUTURES.clear();
    }

    /**
     * 注解扫描任务
     */
    private static class AnnotationScanTask extends RecursiveAction {
        private final Path path;
        private final Class<? extends Annotation> annotationType;
        private final Set<String> resultSet;
        private final boolean classLevel;

        public AnnotationScanTask(Path path, Class<? extends Annotation> annotationType,
                                  Set<String> resultSet, boolean classLevel) {
            this.path = path;
            this.annotationType = annotationType;
            this.resultSet = resultSet;
            this.classLevel = classLevel;
        }

        @Override
        protected void compute() {
            try {
                List<AnnotationScanTask> subTasks = new ArrayList<>();

                Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                        if (file.toString().endsWith(".java")) {
                            // 小文件直接处理
                            if (Files.size(file) < 1024 * 1024) {
                                processFile(file);
                            } else {
                                // 大文件创建子任务
                                subTasks.add(new AnnotationScanTask(file, annotationType, resultSet, classLevel));
                            }
                        }
                        return FileVisitResult.CONTINUE;
                    }

                    @Override
                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                        // 对于目录，创建子任务并行处理
                        if (!path.equals(dir)) {
                            subTasks.add(new AnnotationScanTask(dir, annotationType, resultSet, classLevel));
                            return FileVisitResult.SKIP_SUBTREE;
                        }
                        return FileVisitResult.CONTINUE;
                    }
                });

                // 执行所有子任务
                invokeAll(subTasks);
            } catch (IOException e) {
                throw new RuntimeException("File walk failed", e);
            }
        }

        private void processFile(Path file) {
            try {
                String className = getClassName(file);
                if (className == null) return;

                // 使用安全的类加载方式
                Class<?> clazz = ClassUtils.forName(className, Thread.currentThread().getContextClassLoader());

                if (classLevel) {
                    // 类级别注解检查
                    if (clazz.isAnnotationPresent(annotationType)) {
                        resultSet.add(clazz.getName());
                    }
                } else {
                    // 方法级别注解检查
                    for (Method method : clazz.getDeclaredMethods()) {
                        if (method.isAnnotationPresent(annotationType)) {
                            resultSet.add(clazz.getName());
                            break; // 找到一个就跳出
                        }
                    }
                }
            } catch (ClassNotFoundException | NoClassDefFoundError | ExceptionInInitializerError e) {
                // 忽略无法加载的类
            } catch (Throwable t) {
                // 记录错误但不中断扫描
                System.err.println("Error processing file: " + file + " - " + t.getMessage());
            }
        }
    }

    /**
     * 获取基础扫描路径
     */
    private static Path getBasePath() {
        String localDirectory = System.getProperty("user.dir") + "/src/main/java";
        Path path = Paths.get(localDirectory);
        if (Files.exists(path)) {
            return path;
        }
        return null;
    }


    /**
     * 获取带有@SQL注解的方法列表
     */
    public static List<SQLXMLMethod> getSQLXMLMethod() {
        List<SQLXMLMethod> methods = new ArrayList<>();
        // 获取所有带 SQL 注解的类
        List<String> classesWithAnnotation = ClassesUtils.getClassesWithAnnotation(SQL.class);
        for (String className : classesWithAnnotation) {
            methods.addAll(ClassesUtils.getSQLXMLMethodByClassName(className));
        }
        // 获取项目中所有类
        List<String> classes = getAllClasses();
        for (String aClass : classes) {
            try {
                Class<?> clazz = getClassByCompleteClassName(aClass);
                if (clazz == null) {
                    continue;
                }
                // 获取标注SQL注解的方法
                for (Method method : clazz.getDeclaredMethods()) {
                    if (method.isAnnotationPresent(SQL.class)) {
                        SQLXMLMethod sqlMethod = new SQLXMLMethod();
                        sqlMethod.setClassName(clazz.getName());
                        sqlMethod.setMethodName(method.getName());
                        // 参数值无法在静态扫描中获取，设为空数组
                        sqlMethod.setArgs(new Object[0]);
                        methods.add(sqlMethod);
                    }
                }
            } catch (Exception e) {
                log.error("SQLXMLMethod clazz error", e);
            }
        }
        return methods;
    }

    /**
     * 获取带有@SQL注解的方法列表
     */
    public static List<SQLXMLMethod> getSQLXMLMethodByClassName(String className) {
        List<SQLXMLMethod> methods = new ArrayList<>();
        try {
            Class<?> clazz = getClassByCompleteClassName(className);
            for (Method method : clazz.getDeclaredMethods()) {
                if (method.isAnnotationPresent(SQL.class)) {
                    SQLXMLMethod sqlMethod = new SQLXMLMethod();
                    sqlMethod.setClassName(clazz.getName());
                    sqlMethod.setMethodName(method.getName());
                    // 参数值无法在静态扫描中获取，设为空数组
                    sqlMethod.setArgs(new Object[0]);
                    methods.add(sqlMethod);
                }
            }
        } catch (Exception e) {
            log.error("getSQLXMLMethodByClassName clazz error", e);
        }
        return methods;
    }

    public static boolean matchesSQLXMLMethod(String methodName, List<SQLXMLMethod> methods) {
        return methods.stream()
                .anyMatch(x -> Objects.equals(x.getMethodName(), methodName));
    }

    /**
     * 获取项目中所有类
     */
    public static List<String> getAllClasses() {
        List<String> classNames = new ArrayList<>();
        List<File> aFiles = Lists.newArrayList();
        getAllFile(aFiles);
        aFiles = aFiles.stream().filter(x -> x.getName().contains(".java")).collect(Collectors.toList());
        for (File aFile : aFiles) {
            String absolutePath = aFile.getAbsolutePath();
            String className = getClassName(absolutePath);
            classNames.add(className);
        }
        return classNames;
    }

    private static String getClassName(String absolutePath) {
        String commaAbsolutePath = absolutePath.replaceAll("\\\\", ".");
        return commaAbsolutePath.substring(
                commaAbsolutePath.indexOf("src.main.java") + "src.main.java".length() + 1,
                commaAbsolutePath.lastIndexOf(".java"));
    }

    /**
     * 安全获取类名
     */
    private static String getClassName(Path file) {
        if (BASE_PATH == null) return null;

        try {
            Path relativePath = BASE_PATH.relativize(file);
            return relativePath.toString()
                    .replace(FileSystems.getDefault().getSeparator(), ".")
                    .replace(".java", "");
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    /**
     * 获取 @RequestMapping 注解的 value 值
     *
     * @param className
     * @return
     */
    public static String getRequestMappingClassParentPath(String className) {
        Class<?> aClass = getClassByCompleteClassName(className);
        RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class);
        if (Objects.nonNull(requestMapping)) {
            String[] value = requestMapping.value();
            if (value.length > 0) {
                return SLASH.concat(StringUtils.uncap(value[0]));
            }
        }
        RestPath restPath = aClass.getAnnotation(RestPath.class);
        if (Objects.nonNull(restPath)) {
            String value = restPath.value();
            if (StrUtil.isNotBlank(value)) {
                return value.startsWith(SLASH) ? value : SLASH.concat(StringUtils.uncap(value));
            }
        }
        return "";
    }

    /**
     * 获取 @RequestMapping 标注的类中的 method 和 url 集合
     *
     * @param className
     * @return
     */
    public static List<RequestMethodAndUrl> getRequestMappingClassMethodUrls(String className) {
        String parentPath = getRequestMappingClassParentPath(className);
        List<RequestMethodAndUrl> requestMethodAndUrlList = new ArrayList<>();
        try {
            Class<?> aClass = Class.forName(className);
            Method[] declaredMethods = aClass.getDeclaredMethods();
            for (Method declaredMethod : declaredMethods) {
                RequestMethodAndUrl requestMethodAndUrl = new RequestMethodAndUrl();
                requestMethodAndUrl.setReturnType(declaredMethod.getGenericReturnType());
                requestMethodAndUrl.setClassName(className);
                requestMethodAndUrl.setMethodName(declaredMethod.getName());
                requestMethodAndUrl.setHasSQLAnnotation(declaredMethod.isAnnotationPresent(SQL.class));
                GetMapping getMapping = declaredMethod.getAnnotation(GetMapping.class);
                Optional.ofNullable(getMapping).ifPresent(c -> {
                    String[] value = c.value();
                    String path = 0 == value.length ? SLASH + declaredMethod.getName() : value[0];
                    requestMethodAndUrl.setRequestType("GET");
                    requestMethodAndUrl.setUrl(parentPath + path);
                });
                PostMapping postMapping = declaredMethod.getAnnotation(PostMapping.class);
                Optional.ofNullable(postMapping).ifPresent(c -> {
                    String[] value = c.value();
                    String path = 0 == value.length ? SLASH + declaredMethod.getName() : value[0];
                    requestMethodAndUrl.setRequestType("POST");
                    requestMethodAndUrl.setUrl(parentPath + path);
                    setRequestMethodUrlBodyType(declaredMethod, requestMethodAndUrl, false);
                });
                PutMapping putMapping = declaredMethod.getAnnotation(PutMapping.class);
                Optional.ofNullable(putMapping).ifPresent(c -> {
                    String[] value = c.value();
                    String path = 0 == value.length ? SLASH + declaredMethod.getName() : value[0];
                    requestMethodAndUrl.setRequestType("PUT");
                    requestMethodAndUrl.setUrl(parentPath + path);
                    setRequestMethodUrlBodyType(declaredMethod, requestMethodAndUrl, false);
                });
                DeleteMapping deleteMapping = declaredMethod.getAnnotation(DeleteMapping.class);
                Optional.ofNullable(deleteMapping).ifPresent(c -> {
                    String[] value = c.value();
                    String path = 0 == value.length ? SLASH + declaredMethod.getName() : value[0];
                    requestMethodAndUrl.setRequestType("DELETE");
                    requestMethodAndUrl.setUrl(parentPath + path);
                    setRequestMethodUrlBodyType(declaredMethod, requestMethodAndUrl, true);
                });
                requestMethodAndUrlList.add(requestMethodAndUrl);
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return requestMethodAndUrlList.stream().filter(x -> StrUtil.isNotBlank(x.getUrl())).collect(Collectors.toList());
    }

    private static void setRequestMethodUrlBodyType(Method declaredMethod, RequestMethodAndUrl requestMethodAndUrl,
                                                    Boolean isDelete) {
        Parameter[] parameters = declaredMethod.getParameters();
        Parameter parameter = parameters[0];
        RequestBody requestBodyAnnotation = parameter.getAnnotation(RequestBody.class);
        RequestParam requestParamAnnotation = parameter.getAnnotation(RequestParam.class);
        if (Objects.nonNull(requestBodyAnnotation)) {
            requestMethodAndUrl.setBodyType(0);
        } else if (Objects.nonNull(requestParamAnnotation)) {
            requestMethodAndUrl.setBodyType(1);
        } else {
            if (isDelete) {
                PathVariable pathVariableAnnotation = parameter.getAnnotation(PathVariable.class);
                if (Objects.nonNull(pathVariableAnnotation)) {
                    requestMethodAndUrl.setBodyType(3);
                }
            } else {
                requestMethodAndUrl.setBodyType(2);
            }
        }
    }

    // ==================== 缓存方法（减少开销） ====================

    public static String getCachedClassName(String className) {
        return CLASS_NAME_CACHE.computeIfAbsent(className,
                k -> ClassesUtils.getAllClasses().stream()
                        .filter(x -> x.endsWith(capitalizeFirstLetter(className)))
                        .findFirst()
                        .orElse(null));
    }

    public static List<String> getCachedFields(String className) {
        return MODEL_FIELDS_CACHE.computeIfAbsent(className, k ->
                getFields(className)
        );
    }

    public static Class<?> getCachedModelClass(String className) {
        return MODEL_CLASS_CACHE.computeIfAbsent(className, k ->
                getClassByCompleteClassName(className)
        );
    }

}
